`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2021/09/25 20:40:06
// Design Name: 
// Module Name: e203_subsys_nice_mrt_core
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////

`include "e203_defines.v"

`ifdef E203_HAS_NICE//{
module e203_subsys_nice_mrt_core (
    // System	
    input                         nice_clk             ,
    input                         nice_rst_n	          ,
    output                        nice_active	      ,
    output                        nice_mem_holdup	  ,
//    output                        nice_rsp_err_irq	  ,
    // Control cmd_req
    input                         nice_req_valid       ,
    output                        nice_req_ready       ,
    input  [`E203_XLEN-1:0]       nice_req_inst        ,
    input  [`E203_XLEN-1:0]       nice_req_rs1         ,
    input  [`E203_XLEN-1:0]       nice_req_rs2         ,
    // Control cmd_rsp	
    output                        nice_rsp_valid       ,
    input                         nice_rsp_ready       ,
    output [`E203_XLEN-1:0]       nice_rsp_rdat        ,
    output                        nice_rsp_err    	  ,
    // Memory lsu_req	
    output                        nice_icb_cmd_valid   ,
    input                         nice_icb_cmd_ready   ,
    output [`E203_ADDR_SIZE-1:0]  nice_icb_cmd_addr    ,
    output                        nice_icb_cmd_read    ,
    output [`E203_XLEN-1:0]       nice_icb_cmd_wdata   ,
//    output [`E203_XLEN_MW-1:0]     nice_icb_cmd_wmask   ,  // 
    output [1:0]                  nice_icb_cmd_size    ,
    // Memory lsu_rsp	
    input                         nice_icb_rsp_valid   ,
    output                        nice_icb_rsp_ready   ,
    input  [`E203_XLEN-1:0]       nice_icb_rsp_rdata   ,
    input                         nice_icb_rsp_err	   ,
    // adc enframe block interface
    input                         u_mrt_wen           ,
    input     [24*2-1: 0]         u_mrt_cfg_data      ,
    input                         u_mrt_cfg_last      ,
    //interrupt interface
    output                        u_mrt_finish
);

//   localparam PIPE_NUM = 3;


// here we only use custom3: 
// CUSTOM0 = 7'h0b, R type
// CUSTOM1 = 7'h2b, R tpye
// CUSTOM2 = 7'h5b, R type
// CUSTOM3 = 7'h7b, R type

// RISC-V format  
//	.insn r  0x33,  0,  0, a0, a1, a2       0:  00c58533[ 	]+add [ 	]+a0,a1,a2
//	.insn i  0x13,  0, a0, a1, 13           4:  00d58513[ 	]+addi[ 	]+a0,a1,13
//	.insn i  0x67,  0, a0, 10(a1)           8:  00a58567[ 	]+jalr[ 	]+a0,10 (a1)
//	.insn s   0x3,  0, a0, 4(a1)            c:  00458503[ 	]+lb  [ 	]+a0,4(a1)
//	.insn sb 0x63,  0, a0, a1, target       10: feb508e3[ 	]+beq [ 	]+a0,a1,0 target
//	.insn sb 0x23,  0, a0, 4(a1)            14: 00a58223[ 	]+sb  [ 	]+a0,4(a1)
//	.insn u  0x37, a0, 0xfff                18: 00fff537[ 	]+lui [ 	]+a0,0xfff
//	.insn uj 0x6f, a0, target               1c: fe5ff56f[ 	]+jal [ 	]+a0,0 target
//	.insn ci 0x1, 0x0, a0, 4                20: 0511    [ 	]+addi[ 	]+a0,a0,4
//	.insn cr 0x2, 0x8, a0, a1               22: 852e    [ 	]+mv  [ 	]+a0,a1
//	.insn ciw 0x0, 0x0, a1, 1               24: 002c    [ 	]+addi[ 	]+a1,sp,8
//	.insn cb 0x1, 0x6, a1, target           26: dde9    [ 	]+beqz[ 	]+a1,0 target
//	.insn cj 0x1, 0x5, target               28: bfe1    [ 	]+j   [ 	]+0 targe

   ////////////////////////////////////////////////////////////
   // decode
   ////////////////////////////////////////////////////////////
   wire [6:0] opcode      = {7{nice_req_valid}} & nice_req_inst[6:0];
   wire [2:0] rv32_func3  = {3{nice_req_valid}} & nice_req_inst[14:12];
   wire [6:0] rv32_func7  = {7{nice_req_valid}} & nice_req_inst[31:25];

//   wire opcode_custom0 = (opcode == 7'b0001011); 
//   wire opcode_custom1 = (opcode == 7'b0101011); 
//   wire opcode_custom2 = (opcode == 7'b1011011); 
   wire opcode_custom3 = (opcode == 7'b1111011); 

   wire rv32_func3_000 = (rv32_func3 == 3'b000); 
   wire rv32_func3_001 = (rv32_func3 == 3'b001); 
   wire rv32_func3_010 = (rv32_func3 == 3'b010); 
   wire rv32_func3_011 = (rv32_func3 == 3'b011); 
   wire rv32_func3_100 = (rv32_func3 == 3'b100); 
   wire rv32_func3_101 = (rv32_func3 == 3'b101); 
   wire rv32_func3_110 = (rv32_func3 == 3'b110); 
   wire rv32_func3_111 = (rv32_func3 == 3'b111); 

   wire rv32_func7_0000000 = (rv32_func7 == 7'b0000000); 
   wire rv32_func7_0000001 = (rv32_func7 == 7'b0000001); 
   wire rv32_func7_0000010 = (rv32_func7 == 7'b0000010); 
   wire rv32_func7_0000011 = (rv32_func7 == 7'b0000011); 
   wire rv32_func7_0000100 = (rv32_func7 == 7'b0000100); 
   wire rv32_func7_0000101 = (rv32_func7 == 7'b0000101); 
   wire rv32_func7_0000110 = (rv32_func7 == 7'b0000110); 
   wire rv32_func7_0000111 = (rv32_func7 == 7'b0000111); 

   ////////////////////////////////////////////////////////////
   // custom3:
   // Supported format: only R type here
   // Supported instr:
   //  1. custom3 lbuf: load data(in memory) to row_buf
   //     lbuf (a1)
   //     .insn r opcode, func3, func7, rd, rs1, rs2    
   //  2. custom3 sbuf: store data(in row_buf) to memory
   //     sbuf (a1)
   //     .insn r opcode, func3, func7, rd, rs1, rs2    
   //  3. custom3 acc rowsum: load data from memory(@a1), accumulate row datas and write back 
   //     rowsum rd, a1, x0
   //     .insn r opcode, func3, func7, rd, rs1, rs2    
   ////////////////////////////////////////////////////////////
   wire custom3_rdstat     = opcode_custom3 & rv32_func3_110 & rv32_func7_0000001; 
   wire custom3_start     = opcode_custom3 & rv32_func3_100 & rv32_func7_0000010; 
   // prg nice cmd
   wire custom3_u1     = opcode_custom3 & rv32_func3_110 & rv32_func7_0000101; 
   wire custom3_u2     = opcode_custom3 & rv32_func3_111 & rv32_func7_0000110; 
   wire custom3_u3   = opcode_custom3 & rv32_func3_111 & rv32_func7_0000111; 
   // illegal cmd
   wire custom3_ndef   = ~(custom3_rdstat | custom3_start | custom3_u1 | custom3_u2); 
   ////////////////////////////////////////////////////////////
   //  multi-cyc op 
   ////////////////////////////////////////////////////////////
   wire custom_multi_cyc_op = custom3_rdstat | custom3_start | custom3_ndef;
   // need access memory
   wire custom_mem_op = 1'b0;
   // need return value
   wire custom_ret_op = custom3_rdstat | custom3_start | custom3_ndef;
   
   ////////////////////////////////////////////////////////////
   //  rs register 
   ////////////////////////////////////////////////////////////
 
    wire [`E203_XLEN-1:0] rs1_r;
    wire rs1_ena, rs1_rst_n;
    sirv_gnrl_dfflr #(`E203_XLEN)   rs1_dfflr (rs1_ena, nice_req_rs1, rs1_r, nice_clk, rs1_rst_n);
    assign rs1_ena = nice_req_valid;
    assign rs1_rst_n = nice_rst_n;
    wire [`E203_XLEN-1:0] rs2_r;
    wire rs2_ena, rs2_rst_n;
    sirv_gnrl_dfflr #(`E203_XLEN)   rs2_dfflr (rs2_ena, nice_req_rs2, rs2_r, nice_clk, rs2_rst_n);
    assign rs2_ena = nice_req_valid;
    assign rs2_rst_n = nice_rst_n;

 
   ////////////////////////////////////////////////////////////
   // NICE FSM 
   ////////////////////////////////////////////////////////////
   parameter NICE_FSM_WIDTH = 3; 
   parameter IDLE          = 3'b000; 
   parameter RDSTAT        = 3'b100; 
   parameter START         = 3'b001; 
   parameter NDEF         = 3'b010; 

   wire [NICE_FSM_WIDTH-1:0] state_r; 
   wire [NICE_FSM_WIDTH-1:0] nxt_state; 
   wire [NICE_FSM_WIDTH-1:0] state_idle_nxt; 
   wire [NICE_FSM_WIDTH-1:0] state_rdstat_nxt; 
   wire [NICE_FSM_WIDTH-1:0] state_start_nxt; 
   wire [NICE_FSM_WIDTH-1:0] state_ndef_nxt; 

   wire nice_req_hsked;
   wire nice_rsp_hsked;
   wire nice_icb_rsp_hsked;
   wire illgel_instr = ~(custom_multi_cyc_op);

   wire state_idle_exit_ena; 
   wire state_rdstat_exit_ena; 
   wire state_start_exit_ena; 
   wire state_ndef_exit_ena; 
   
   wire state_ena; 

   wire state_is_idle       = (state_r == IDLE); 
   wire state_is_rdstat     = (state_r == RDSTAT); 
   wire state_is_start      = (state_r == START); 
   wire state_is_ndef       = (state_r == NDEF); 

   assign state_idle_exit_ena = state_is_idle & nice_req_hsked & ~illgel_instr; 
   assign state_idle_nxt =  custom3_rdstat    ? RDSTAT   : 
                            custom3_start     ? START    :
                            custom3_ndef      ? NDEF     :
			    IDLE;

   wire rdstat_done; 
   assign state_rdstat_exit_ena = state_is_rdstat & rdstat_done; 
   assign state_rdstat_nxt = IDLE;

   wire start_done; 
   assign state_start_exit_ena = state_is_start & start_done; 
   assign state_start_nxt = IDLE;

   wire ndef_done; 
   assign state_ndef_exit_ena = state_is_ndef & ndef_done; 
   assign state_ndef_nxt = IDLE;

   assign nxt_state =   ({NICE_FSM_WIDTH{state_idle_exit_ena    }} & state_idle_nxt    )
                      | ({NICE_FSM_WIDTH{state_rdstat_exit_ena  }} & state_rdstat_nxt  )
                      | ({NICE_FSM_WIDTH{state_start_exit_ena   }} & state_start_nxt   ) 
                      | ({NICE_FSM_WIDTH{state_ndef_exit_ena   }} & state_ndef_nxt   ) 
                      ;

   assign state_ena =   state_idle_exit_ena | state_rdstat_exit_ena 
                      | state_start_exit_ena | state_ndef_exit_ena;

   sirv_gnrl_dfflr #(NICE_FSM_WIDTH)   state_dfflr (state_ena, nxt_state, state_r, nice_clk, nice_rst_n);

   ////////////////////////////////////////////////////////////
   // instr EXU
   ////////////////////////////////////////////////////////////

   //wire [COL_IDX_W-1:0]  rownum;

   //////////// 1. custom3_rdstat
   
   wire [`E203_XLEN-1:0] u42a_r, u42a_nxt;
   wire u42a_ena, u42a_rst_n;
   sirv_gnrl_dfflr #(`E203_XLEN)   u42a_dfflr (u42a_ena, u42a_nxt, u42a_r, nice_clk, u42a_rst_n);
   wire [`E203_XLEN-1:0] sigma_r, sigma_nxt;
   wire sigma_ena, sigma_rst_n;
   sirv_gnrl_dfflr #(`E203_XLEN)   sigma_dfflr (sigma_ena, sigma_nxt, sigma_r, nice_clk, sigma_rst_n);
  wire [`E203_XLEN-1:0] gamma_r, gamma_nxt;
   wire gamma_ena, gamma_rst_n;
   sirv_gnrl_dfflr #(`E203_XLEN)   gamma_dfflr (gamma_ena, gamma_nxt, gamma_r, nice_clk, gamma_rst_n);
  wire [`E203_XLEN-1:0] psy_r, psy_nxt;
   wire psy_ena, psy_rst_n;
   sirv_gnrl_dfflr #(`E203_XLEN)   psy_dfflr (psy_ena, psy_nxt, psy_r, nice_clk, psy_rst_n);
   wire u42a_status_r;
   wire u42a_status_ena, u42a_status_rst_n;
   sirv_gnrl_dfflr #(1)   u42a_status_dfflr (u42a_status_ena, 1'b1, u42a_status_r, nice_clk, u42a_status_rst_n);
   wire sigma_status_r;
   wire sigma_status_ena, sigma_status_rst_n;
   sirv_gnrl_dfflr #(1)   sigma_status_dfflr (sigma_status_ena, 1'b1, sigma_status_r, nice_clk, sigma_status_rst_n);
   wire gamma_status_r;
   wire gamma_status_ena, gamma_status_rst_n;
   sirv_gnrl_dfflr #(1)   gamma_status_dfflr (gamma_status_ena, 1'b1, gamma_status_r, nice_clk, gamma_status_rst_n);
   wire psy_status_r;
   wire psy_status_ena, psy_status_rst_n;
   sirv_gnrl_dfflr #(1)   psy_status_dfflr (psy_status_ena, 1'b1, psy_status_r, nice_clk, psy_status_rst_n);
   wire workmode_status_r, workmode_status_nxt;
   wire workmode_status_ena, workmode_status_rst_n;
   sirv_gnrl_dfflr #(1)   workmode_status_dfflr (workmode_status_ena, workmode_status_nxt, workmode_status_r, nice_clk, workmode_status_rst_n);
   wire busy_status_r;
   wire busy_status_ena, busy_status_rst_n;
   sirv_gnrl_dfflr #(1)   busy_status_dfflr (busy_status_ena, ~busy_status_r, busy_status_r, nice_clk, busy_status_rst_n);

   wire [`E203_XLEN-1:0] rdstat_res;
   wire nice_rsp_valid_rdstat;
   assign rdstat_res = state_is_rdstat ? (rs1_r==32'h0000_0000) ? {26'b0,workmode_status_r,psy_status_r,gamma_status_r,u42a_status_r,sigma_status_r,busy_status_r} 
                                       : (rs1_r==32'h0000_0001) ? u42a_r
                                       : (rs1_r==32'h0000_0002) ? sigma_r
                                       : (rs1_r==32'h0000_0003) ? gamma_r
                                       : (rs1_r==32'h0000_0004) ? psy_r
                                       : (rs1_r[31]==1'b1) ? {26'b0,rs1_r[5],psy_status_r,gamma_status_r,u42a_status_r,sigma_status_r,busy_status_r}
                                       : 32'b0
                                   :32'b0;
   assign nice_rsp_valid_rdstat = state_is_rdstat;
   assign rdstat_done = state_is_rdstat & nice_rsp_hsked;

   assign workmode_status_ena = state_is_rdstat & rs1_r[31];
   assign workmode_status_rst_n = nice_rst_n;
   assign workmode_status_nxt = rs1_r[5];

   //////////// 2. custom3_start
   wire [`E203_XLEN-1:0] start_res;
   wire nice_rsp_valid_start;
   wire mrt_rstn;
   wire [`E203_XLEN-1:0] u42a_data, sigma_dp_data, gamma_data, psy_data;
   wire u42a_data_valid, sigma_dp_data_valid, gamma_data_valid, psy_data_valid;
   wire u_mrt_ena;

   //////// Core
       MRT_wrapper u_mrt(
       .i_clk                  (nice_clk),
       .i_rstn                 (mrt_rstn),
       .i_ena                  (u_mrt_ena),
       .i_wen                  (u_mrt_wen),
       .i_cfg_data             (u_mrt_cfg_data),
       .i_cfg_last             (u_mrt_cfg_last),
       .work_mode              (workmode_status_r),
       .u42a_data              (u42a_data),
       .u42a_data_valid        (u42a_data_valid),
       .sigma_dp_data          (sigma_dp_data),
       .sigma_dp_data_valid    (sigma_dp_data_valid),
       .psy_data               (psy_data),
       .psy_data_valid         (psy_data_valid),
       .gama_m_data            (gamma_data),
       .gama_m_data_valid      (gamma_data_valid)
        );
    
    
   wire mrt_finish;
   wire mrt_finish_nxt;
   assign mrt_rstn = busy_status_r;
   assign mrt_finish_nxt = workmode_status_r ? gamma_data_valid : u42a_data_valid;
   sirv_gnrl_dfflr #(1)   mrt_finish_dfflr (1'b1, mrt_finish_nxt, mrt_finish, nice_clk, nice_rst_n);

   assign start_res = {31'b0,~(state_is_start&busy_status_r)};
   assign nice_rsp_valid_start = state_is_start;
   assign start_done = state_is_start & nice_rsp_hsked;
   assign u_mrt_finish = mrt_finish;
   assign u_mrt_ena = 1'b1;
   assign busy_status_ena = state_start_exit_ena;
   assign busy_status_rst_n = nice_rst_n;
   
   assign u42a_rst_n = nice_rst_n;
   assign sigma_rst_n = nice_rst_n;
   assign gamma_rst_n = nice_rst_n;
   assign psy_rst_n = nice_rst_n;
   assign u42a_ena = u42a_data_valid;
   assign sigma_ena = sigma_dp_data_valid;
   assign gamma_ena = gamma_data_valid;
   assign psy_ena = psy_data_valid;
   assign u42a_status_ena = u42a_data_valid;
   assign sigma_status_ena = sigma_dp_data_valid;
   assign psy_status_ena = psy_data_valid;
   assign gamma_status_ena = gamma_data_valid;
   assign u42a_status_rst_n = nice_rst_n & ~(state_is_start & busy_status_r);
   assign sigma_status_rst_n = nice_rst_n & ~(state_is_start & busy_status_r);
   assign psy_status_rst_n = nice_rst_n & ~(state_is_start & busy_status_r);
   assign gamma_status_rst_n = nice_rst_n & ~(state_is_start & busy_status_r);
   assign u42a_nxt = u42a_data;
   assign sigma_nxt = sigma_dp_data;
   assign gamma_nxt = gamma_data;
   assign psy_nxt = psy_data;
   
   //////////// 3. custom3_ndef

      wire [`E203_XLEN-1:0] ndef_res;
      wire nice_rsp_valid_ndef ;
      // if cmd is not defined return ndef error code: 0x7fff0000
      assign ndef_res = 32'h7fff_0000;
      assign nice_rsp_valid_ndef = state_is_ndef;
      assign ndef_done = state_is_ndef & nice_rsp_hsked;

   ////////////////////////////////////////////////////////////
   // Control cmd_req
   ////////////////////////////////////////////////////////////
   assign nice_req_hsked = nice_req_valid & nice_req_ready;
   assign nice_req_ready = state_is_idle & (custom_mem_op ? nice_icb_cmd_ready : 1'b1);

   ////////////////////////////////////////////////////////////
   // Control cmd_rsp
   ////////////////////////////////////////////////////////////
   assign nice_rsp_hsked = nice_rsp_valid & nice_rsp_ready; 
   assign nice_icb_rsp_hsked = nice_icb_rsp_valid & nice_icb_rsp_ready;
   assign nice_rsp_valid = nice_rsp_valid_rdstat | nice_rsp_valid_start | nice_rsp_valid_ndef;
   assign nice_rsp_rdat  = {`E203_XLEN{state_is_rdstat}} & rdstat_res
                         | {`E203_XLEN{state_is_start }} & start_res
                         | {`E203_XLEN{state_is_ndef }} & ndef_res
                           ;

   // memory access bus error
   //assign nice_rsp_err_irq  =   (nice_icb_rsp_hsked & nice_icb_rsp_err)
   //                          | (nice_req_hsked & illgel_instr)
   //                          ; 
   assign nice_rsp_err   =   (nice_icb_rsp_hsked & nice_icb_rsp_err);

   ////////////////////////////////////////////////////////////
   // Memory lsu
   ////////////////////////////////////////////////////////////
   // memory access list:
   //  1. In IDLE, custom_mem_op will access memory(lbuf/sbuf/rowsum)
   //  2. In LBUF, it will read from memory as long as lbuf_cnt_r is not full
   //  3. In SBUF, it will write to memory as long as sbuf_cnt_r is not full
   //  3. In ROWSUM, it will read from memory as long as rowsum_cnt_r is not full
   //assign nice_icb_rsp_ready = state_is_ldst_rsp & nice_rsp_ready; 
   // rsp always ready
   assign nice_icb_rsp_ready = 1'b1; 

   assign nice_icb_cmd_valid =  1'b0;
   assign nice_icb_cmd_addr  = `E203_XLEN'b0;
   assign nice_icb_cmd_read  = 1'b1;
   assign nice_icb_cmd_wdata = `E203_XLEN'b0; 

   //assign nice_icb_cmd_wmask = {`sirv_XLEN_MW{custom3_sbuf}} & 4'b1111;
   assign nice_icb_cmd_size  = 2'b10;
   assign nice_mem_holdup    =  1'b0; 

   ////////////////////////////////////////////////////////////
   // nice_active
   ////////////////////////////////////////////////////////////
   assign nice_active = state_is_idle ? nice_req_valid : 1'b1;

endmodule
`endif//}
